﻿using System;
using System.Collections.Generic;
using System.Text;

using Microsoft.Xna.Framework.Graphics;

using Daybreak.Core.Rendering.Pipeline;
using Microsoft.Xna.Framework;

namespace Daybreak.Core.SceneGraph
{
    /// <summary>
    /// The light object declares a light source that illuminates the scene. 
    /// Light sources have many different properties and radiate light in many different patterns and frequencies. 
    /// </summary>
    public class Light : Node
    {
        /// <summary>
        /// Base class for lighting technique
        /// </summary>
        public abstract class Technique
        {
            public abstract void UpdateFrameData(Pipes.FrameContext frameData, ref RenderArgs args);

        }

        /// <summary>
        /// Lighting technique for this light source
        /// </summary>
        public Technique LightTechnique;

        public Light()
        {
        }


        public override void Accept(NodeVisitor visitor)
        {
            visitor.VisitLight(this);
        }

        public override void UpdateFrameData(Pipes.FrameContext frameData, ref RenderArgs args)
        {
            if (LightTechnique != null)
                LightTechnique.UpdateFrameData(frameData, ref args);
        }

        public override void Update(NodeVisitor updater, float deltaTime)
        {
            base.Update(updater, deltaTime);
        }
    }

    /// <summary>
    /// The ambient lighting technique declares the parameters required to describe an ambient light source. 
    /// An ambient light is one that lights everything evenly, regardless of location or orientation. 
    /// </summary>
    public class AmbientLight : Light.Technique
    {
        public Color Color;

        public AmbientLight() { }

        public AmbientLight(Color color)
        {
            Color = color;
        }

        public static Light Node(Color color)
        {
            Light light = new Light();
            light.LightTechnique = new AmbientLight(color);

            return light;
        }

        public override void UpdateFrameData(Pipes.FrameContext frameData, ref RenderArgs args)
        {
            Sas.AmbientLightColor color = frameData.GetAttribute<Sas.AmbientLightColor>(SceneObject.AmbientLight);

            color.Value = Color;
        }
    }

    /// <summary>
    /// The directional lighting technique declares the parameters required to describe a directional light source. 
    /// A directional light is one that lights everything from the same direction, regardless of location. 
    /// The light??™s default direction vector in local coordinates is [0,0,-1], pointing down the -Z axis. 
    /// The actual direction of the light is defined by the transform of the node where the light is instantiated. 
    /// </summary>
    public class DirectionalLight : Light.Technique
    {
        public Color DiffuseColor;
        public Color SpecularColor;

        public DirectionalLight() { }

        public DirectionalLight(Color color)
        {
            DiffuseColor = color;
            SpecularColor = Color.White;
        }

        public static Light Node(Color color)
        {
            Light light = new Light();
            light.LightTechnique = new DirectionalLight(color);

            return light;
        }


        public override void UpdateFrameData(Pipes.FrameContext frameData, ref RenderArgs args)
        {
            Vector3 vec = args.TransformMatrix.Translation;
            vec.Normalize();

            vec.X = -vec.X;
            vec.Y = -vec.Y;
            vec.Z = -vec.Z;

            Sas.LightDirection dir = frameData.GetAttribute<Sas.LightDirection>(SceneObject.DirectionalLight);
            dir.Value = vec;

            Sas.DiffuseLightColor dcolor = frameData.GetAttribute<Sas.DiffuseLightColor>(SceneObject.DirectionalLight);
            dcolor.Value = DiffuseColor;

            Sas.SpecularLightColor scolor = frameData.GetAttribute<Sas.SpecularLightColor>(SceneObject.DirectionalLight);
            scolor.Value = SpecularColor;

            Sas.LightPosition lPos = frameData.GetAttribute<Sas.LightPosition>(SceneObject.PointLight);
            lPos.Value = args.TransformMatrix.Translation;


        }
    }
}
